home *** CD-ROM | disk | FTP | other *** search
- #if !COMPILER
- /*
- * File: imain.r
- * Interpreter main program, argument handling, and such.
- * Contents: main, icon_call, icon_setup, resolve, xmfree
- */
-
- #include "../h/version.h"
- #include "../h/header.h"
- #include "../h/opdefs.h"
-
- /*
- * Prototypes.
- */
-
- hidden novalue env_err Params((char *msg,char *name,char *val));
- hidden novalue icon_setup Params((int argc, char **argv, int *ip));
-
- /*
- * The following code is operating-system dependent [@imain.01]. Declarations
- * that are system-dependent.
- */
-
- #if PORT
- /* probably needs something more */
- Deliberate Syntax Error
- #endif /* PORT */
-
- #if MACINTOSH
- #if MPW
- int NoOptions = 0;
- #endif /* MPW */
- #endif /* MACINTOSH */
-
- #if AMIGA || ARM || ATARI_ST || MSDOS || MVS || VM || OS2 || UNIX\
- || VMS
- /* nothing needed */
- #endif /* AMIGA || ARM || ATARI_ST ... */
-
- /*
- * End of operating-system specific code.
- */
-
- #ifdef MemMon
-
- extern FILE *monfile;
-
- char *monfname;
- #endif /* MemMon */
-
- #ifndef MaxHeader
- #define MaxHeader MaxHdr
- #endif /* MaxHeader */
-
- /*
- * A number of important variables follow.
- */
-
- int n_globals = 0; /* number of globals */
- int n_statics = 0; /* number of statics */
-
- #ifdef TraceBack
- #endif /* TraceBack */
-
-
- #ifdef IconCalling
- int IDepth = 0; /* depth of icon_call calls */
- int call_error = 0; /* called procedure not found */
- int interp_status; /* interpreter status */
- #endif /* IconCalling */
-
- int set_up = 0; /* initialization switch */
-
-
- /*
- * Initial icode sequence. This is used to invoke the main procedure with one
- * argument. If main returns, the Op_Quit is executed.
- */
- word istart[3];
- int mterm = Op_Quit;
-
- #ifdef IconCalling
- int fterm = Op_FQuit;
- #endif /* IconCalling */
-
- #ifndef IconCalling
-
-
- novalue main(argc, argv)
-
- int argc;
- char **argv;
- {
- int i, slen;
-
- #if AMIGA
- #if AZTEC_C
- struct Process *FindTask();
- struct Process *Process = FindTask(0L);
- ULONG stacksize = *((ULONG *)Process->pr_ReturnAddr);
-
- if (stacksize < ICONXMINSTACK) {
- fprintf(stderr,"Iconx needs \"stack %d\" to run\n",ICONXMINSTACK);
- exit(-1);
- }
- #endif /* AZTEC_C */
- #endif /* AMIGA */
-
- #if SASC
- quiet(1); /* suppress C library diagnostics */
- #endif /* SASC */
-
- ipc.opnd = NULL;
-
- #if VMS
- redirect(&argc, argv, 0);
- #endif /* VMS */
-
- /*
- * Setup Icon interface. It's done this way to avoid duplication
- * of code, since the same thing has to be done if calling Icon
- * is enabled. See istart.c.
- */
-
- #ifdef CRAY
- argv[0] = "iconx";
- #endif /* CRAY */
-
- icon_setup(argc, argv, &i);
-
- if (i < 0) {
- argc++;
- argv--;
- i++;
- }
-
- while (i--) { /* skip option arguments */
- argc--;
- argv++;
- }
-
- if (!argc)
- error("no icode file specified");
- /*
- * Call icon_init with the name of the icode file to execute. [[I?]]
- */
-
-
- icon_init(argv[1]);
-
- /*
- * Point sp at word after b_coexpr block for &main, point ipc at initial
- * icode segment, and clear the gfp.
- */
-
- stackend = stack + mstksize/WordSize;
- sp = stack + Wsizeof(struct b_coexpr);
-
- ipc.opnd = istart;
- *ipc.op++ = Op_Invoke; /* [[I?]] */
-
- #if AMIGA
- istart[0] = Op_Invoke;
- istart[1] = 1;
- istart[2] = Op_Quit;
- #else /* AMIGA */
- *ipc.opnd++ = 1;
- *ipc.op = Op_Quit;
- ipc.opnd = istart;
- #endif /* AMIGA */
-
- gfp = 0;
-
- /*
- * Set up expression frame marker to contain execution of the
- * main procedure. If failure occurs in this context, control
- * is transferred to mterm, the address of an Op_Quit.
- */
- efp = (struct ef_marker *)(sp);
- efp->ef_failure.op = &mterm;
- efp->ef_gfp = 0;
- efp->ef_efp = 0;
- efp->ef_ilevel = 1;
- sp += Wsizeof(*efp) - 1;
-
- pfp = 0;
- ilevel = 0;
-
- /*
- * We have already loaded the
- * icode and initialized things, so it's time to just push main(),
- * build an Icon list for the rest of the arguments, and called
- * interp on a "invoke 1" bytecode.
- */
- /*
- * The first global variable holds the value of "main". If it
- * is not of type procedure, this is noted as run-time error 117.
- * Otherwise, this value is pushed on the stack.
- */
- if (globals[0].dword != D_Proc)
- fatalerr(117, NULL);
- PushDesc(globals[0]);
- PushNull;
- argp = (dptr)(sp - 1);
-
- /*
- * If main() has a parameter, it is to be invoked with one argument, a list
- * of the command line arguments. The command line arguments are pushed
- * on the stack as a series of descriptors and Ollist is called to create
- * the list. The null descriptor first pushed serves as Arg0 for
- * Ollist and receives the result of the computation.
- */
-
- if (((struct b_proc *)BlkLoc(globals[0]))->nparam > 0) {
- for (i = 2; i < argc; i++) {
- char *tmp;
- slen = strlen(argv[i]);
- PushVal(slen);
- Protect(tmp=alcstr(argv[i],(word)slen), fatalerr(0,NULL));
- PushAVal(tmp);
- }
-
- Ollist(argc - 2, argp);
- }
-
-
- sp = (word *)argp + 1;
- argp = 0;
-
- set_up = 1; /* post fact that iconx is initialized */
-
- /*
- * Start things rolling by calling interp. This call to interp
- * returns only if an Op_Quit is executed. If this happens,
- * c_exit() is called to wrap things up.
- */
-
- #ifdef CoProcesses
- codisp(); /* start up co-expr dispatcher, which will call interp */
- #else /* CoProcesses */
- interp(0,(dptr)NULL); /* [[I?]] */
- #endif /* CoProcesses */
-
- c_exit(NormalExit);
- }
- #endif /* IconCalling */
-
- #ifdef IconCalling
- /*
- * icon_call - call an Icon procedure from a C program.
- */
- dptr icon_call(pname, argc, dargv)
- char *pname;
- int argc;
- dptr dargv;
- {
- int i;
- dptr retdesc;
- struct descrip pd;
-
- #if SASC
- quiet(1); /* suppress C library diagnostics */
- #endif /* SASC */
-
- if (IDepth == 0)
- {
- /*
- * Perform first-time initializations.
- * Point sp at word after b_coexpr block for &main, point ipc at initial
- * icode segment, and clear the gfp.
- */
- stackend = stack + mstksize/WordSize;
- sp = stack + Wsizeof(struct b_coexpr);
- sp--; /* point at last thing on stack, not beyond it */
-
- interp_status = 0;
- argp = 0;
- pfp = 0;
- ilevel = 0;
- }
-
- /*
- * Point sp at word after b_coexpr block for &main, point ipc at initial
- * icode segment, and clear the gfp.
- */
- ipc.opnd = istart;
- *ipc.op++ = Op_Invoke;
- *ipc.opnd++ = argc; /* number of arguments for call */
- *ipc.op = Op_Quit;
-
- ipc.opnd = istart;
- gfp = 0;
-
- /*
- * Set up expression frame marker to contain execution of the
- * main procedure. If failure occurs in this context, control
- * is transferred to fterm, the address of an Op_FQuit.
- */
- efp = (struct ef_marker *)(sp + 1);
- efp->ef_failure.op = &fterm; /* signals a failure to interp */
- efp->ef_gfp = 0;
- efp->ef_efp = 0;
- efp->ef_ilevel = ilevel + 1;
- sp += Wsizeof(*efp);
-
- /*
- * "main" is no longer the default starting procedure.
- * Use procedure named pname as the main (starting) procedure.
- */
- if (getvar(pname,&pd) == Failed) {
- fprintf(stderr, "Icon function/procedure \"%s\" not found\n", pname);
- fflush(stderr);
- call_error = 1;
- return (dptr)NULL;
- }
- Deref(pd); /* get value (can't fail) */
-
- /*
- * Must be of type procedure.
- */
- if ((pd.dword != D_Proc)) {
- if (strcmp(pname,"main") == 0 && (pfp == 0))
- fatalerr(117, NULL);
- else {
- if (pfp == 0)
- fatalerr(106, NULL);
- else
- fatalerr(106, NULL);
- }
- }
-
- PushDesc(pd);
-
- /*
- * The input arguments are pushed on the stack as a series
- * of descriptors and the indicated procedure. The procedure descriptor
- * is overwritten with the result of the call.
- */
- for (i = 0; i < argc; i++) { /* i = 0, instead of 2 */
- PushDesc(dargv[i]);
- }
-
- /* Pass on value of argp to current invocation. This will be 0 by
- * default on the first action, and the value of the current argp on
- * subsequent invocations.
- */
-
- /*
- * Start things rolling by calling interp. This call to interp
- * returns only if an Op_Quit is executed. If this happens,
- * return the result of main. (Used to c_exit here).
- */
- IDepth++;
-
- #ifdef CoProcesses
- codisp(); /* start up co-expr dispatcher, which calls interp */
- #else /* CoProcesses */
- interp(0,(dptr)NULL);
- #endif /* CoProcesses */
-
- IDepth--;
- if (interp_status == A_Pfail_uw)
- return (dptr)NULL; /* failure no value */
- else /* NOTE: suspension not identified */
- {
- retdesc = (dptr)(sp - 1);
- sp = (word *) efp - 1;
- return retdesc; /* success, return top sp */
- }
-
- }
- #endif /* IconCalling */
-
- /*
- * icon_setup - handle interpreter command line options.
- */
- static novalue icon_setup(argc,argv,ip)
- int argc;
- char **argv;
- int *ip;
- {
-
- #ifdef TallyOpt
- extern int tallyopt;
- #endif /* TallyOpt */
-
- *ip = 0; /* number of arguments processed */
-
- #ifdef ExecImages
- if (dumped) {
- /*
- * This is a restart of a dumped interpreter. Normally, argv[0] is
- * iconx, argv[1] is the icode file, and argv[2:(argc-1)] are the
- * arguments to pass as a list to main(). For a dumped interpreter
- * however, argv[0] is the executable binary, and the first argument
- * for main() is argv[1]. The simplest way to handle this is to
- * back up argv to point at argv[-1] and increment argc, giving the
- * illusion of an additional argument at the head of the list. Note
- * that this argument is never referenced.
- */
- argv--;
- argc++;
- (*ip)--;
- }
- #endif /* ExecImages */
-
- #ifdef MaxLevel
- maxilevel = 0;
- maxplevel = 0;
- maxsp = 0;
- #endif /* MaxLevel */
-
- #if MACINTOSH
- #if MPW
- InitCursorCtl(NULL);
- /*
- * To support the icode and iconx interpreter bundled together in
- * the same file, we might have to use this code file as the icode
- * file, too. We do this if the command name is not 'iconx'.
- */
- {
- char *p,*q,c,fn[6];
-
- /*
- * Isolate the filename from the path.
- */
- q = strrchr(*argv,':');
- if (q == NULL)
- q = *argv;
- else
- ++q;
- /*
- * See if it's the real iconx -- case independent compare.
- */
- p = fn;
- if (strlen(q) == 5)
- while (c = *q++) *p++ = tolower(c);
- *p = '\0';
- if (strcmp(fn,"iconx") != 0) {
- /*
- * This technique of shifting arguments relies on the fact that
- * argv[0] is never referenced, since this will make it invalid.
- */
- --argv;
- ++argc;
- --(*ip);
- /*
- * We don't want to look for any command line options in this
- * case. They could interfere with options for the icon
- * program.
- */
- NoOptions = 1;
- }
- }
- #endif /* MPW */
- #endif /* MACINTOSH */
-
- /*
- * Handle command line options.
- */
- #if MACINTOSH && MPW
- if (!NoOptions)
- #endif /* MACINTOSH && MPW */
- while ( argv[1] != 0 && *argv[1] == '-' ) {
- switch ( *(argv[1]+1) ) {
-
- #ifdef TallyOpt
- /*
- * Set tallying flag if -T option given
- */
- case 'T':
- tallyopt = 1;
- break;
- #endif /* TallyOpt */
-
- #ifdef MemMon
- /*
- * Check for command-line event monitor enable
- */
- case 'E': {
- char *p;
- if ( *(argv[1]+2) != '\0' )
- p = argv[1]+2;
- else {
- argv++;
- argc--;
- (*ip)++;
- p = argv[1];
- if ( !p )
- error("no file name given for event monitor file");
- }
- monfname = p;
- break;
- }
- #endif /* MemMon */
-
-
- /*
- * Set stderr to new file if -e option is given.
- */
- case 'e': {
- char *p;
- if ( *(argv[1]+2) != '\0' )
- p = argv[1]+2;
- else {
- argv++;
- argc--;
- (*ip)++;
- p = argv[1];
- if ( !p )
- error("no file name given for redirection of &errout");
- }
- if (!redirerr(p))
- syserr("Unable to redirect &errout\n");
- break;
- }
- }
- argc--;
- (*ip)++;
- argv++;
- }
- }
-
- /*
- * resolve - perform various fix-ups on the data read from the icode
- * file.
- */
- novalue resolve()
-
- {
- register word i, j;
- register struct b_proc *pp;
- register dptr dp;
- extern Omkrec();
- extern int ftsize;
-
-
- /* delete this Xfer */
-
-
- #ifdef EventMon
- if (EventStream)
- fprintf(monfile,"%d(\n",C_Symbols);
- #endif /* EventMon */
-
- /*
- * Relocate the names of the global variables.
- */
- for (dp = gnames; dp < egnames; dp++)
- StrLoc(*dp) = strcons + (uword)StrLoc(*dp);
-
- /*
- * Scan the global variable array for procedures and fill in appropriate
- * addresses.
- */
- for (j = 0; j < n_globals; j++) {
-
- #ifdef EventMon
- EVFnc(j);
- #endif /* EventMon */
-
- if (globals[j].dword != D_Proc)
- continue;
-
- /*
- * The second word of the descriptor for procedure variables tells
- * where the procedure is. Negative values are used for built-in
- * procedures and positive values are used for Icon procedures.
- */
- i = IntVal(globals[j]);
-
- if (i < 0) {
- /*
- * globals[j] points to a built-in function; call (bi_)strprc
- * to look it up by name in the interpreter's table of built-in
- * functions.
- */
- if((BlkLoc(globals[j])= (union block *)bi_strprc(gnames+j,0)) == NULL)
- globals[j] = nulldesc; /* undefined, set to &null */
- }
- else {
-
- /*
- * globals[j] points to an Icon procedure or a record; i is an offset
- * to location of the procedure block in the code section. Point
- * pp at the block and replace BlkLoc(globals[j]).
- */
- pp = (struct b_proc *)(code + i);
- BlkLoc(globals[j]) = (union block *)pp;
-
- /*
- * Relocate the address of the name of the procedure.
- */
- StrLoc(pp->pname) = strcons + (uword)StrLoc(pp->pname);
-
-
- if (pp->ndynam == -2) {
- /*
- * This procedure is a record constructor. Make its entry point
- * be the entry point of Omkrec().
- */
- pp->entryp.ccode = Omkrec;
-
- #ifdef FieldNames
- /*
- * Initialize field names
- */
- for (i = 0; i < pp->nfields; i++)
- StrLoc(pp->lnames[i]) = strcons + (uword)StrLoc(pp->lnames[i]);
- #endif /* FieldNames */
-
- }
- else {
- /*
- * This is an Icon procedure. Relocate the entry point and
- * the names of the parameters, locals, and static variables.
- */
- pp->entryp.icode = code + pp->entryp.ioff;
- for (i = 0; i < abs((int)pp->nparam)+pp->ndynam+pp->nstatic; i++)
- StrLoc(pp->lnames[i]) = strcons + (uword)StrLoc(pp->lnames[i]);
- }
-
- }
-
- }
-
- /*
- * Relocate the names of the fields.
- */
-
- for (dp = fnames; dp < efnames; dp++)
- StrLoc(*dp) = strcons + (uword)StrLoc(*dp);
-
-
- #ifdef EventMon
- if (EventStream)
- fprintf(monfile,"%d)\n%d(",C_Symbols,C_Eval);
- #endif /* EventMon */
- }
-
-
- /*
- * Free malloc-ed memory; the main regions then co-expressions. Note:
- * this is only correct if all allocation is done by routines that are
- * compatible with free() -- which may not be the case if Allocreg()
- * in rmemfix.c is defined to be other than malloc().
- */
-
- novalue xmfree()
- {
- #ifdef FixedRegions
- register struct b_coexpr **ep, *xep;
- register struct astkblk *abp, *xabp;
-
- if (mainhead != (struct b_coexpr *)NULL)
- free((pointer)mainhead->es_actstk); /* activation block for &main */
- free((pointer)code); /* icode */
- code = NULL;
- free((pointer)stack); /* interpreter stack */
- stack = NULL;
- free((pointer)strbase); /* allocated string region */
- strbase = NULL;
- free((pointer)blkbase); /* allocated block region */
- blkbase = NULL;
- free((pointer)quallist); /* qualifier list */
- quallist = NULL;
-
- /*
- * The co-expression blocks are linked together through their
- * nextstk fields, with stklist pointing to the head of the list.
- * The list is traversed and each stack is freeing.
- */
- ep = &stklist;
- while (*ep != NULL) {
- xep = *ep;
- *ep = (*ep)->nextstk;
- /*
- * Free the astkblks. There should always be one and it seems that
- * it's not possible to have more than one, but nonetheless, the
- * code provides for more than one.
- */
- for (abp = xep->es_actstk; abp; ) {
- xabp = abp;
- abp = abp->astk_nxt;
- free((pointer)xabp);
- }
-
- #if CoProcesses
- coswitch(BlkLoc(k_current)->coexpr.cstate, xep->cstate, -1);
- /* terminate coproc for coexpression first */
- #endif /* CoProcesses */
-
- free((pointer)xep);
- stklist = NULL;
- }
- #endif /* Fixed Regions */
-
- }
- #endif /* !COMPILER */
-